<template>
  <div class="page">
    <div class="main">
      <div class="toolbar">
        <input
          v-model="searchQuery"
          type="text"
          placeholder="搜索... 回车执行"
          @keyup.enter="onSearch"
        />
        <button @click="onSearch">搜索</button>
        <button @click="onClearSearch">清空</button>
        <button @click="onExportCsv">导出CSV</button>
        <button @click="onMerge">合并选区</button>
        <button @click="onUnmerge">取消合并</button>
        <button @click="loadReportData">刷新数据</button>
        <button @click="onSave">保存</button>
      </div>

      <div v-if="loading" class="loading-overlay">
        <div class="loading-spinner">数据加载中...</div>
      </div>
      <div v-if="errorMessage" class="error-message">
        <span class="error-icon">⚠️</span>
        <span>{{ errorMessage }}</span>
        <button @click="loadReportData" class="retry-btn">重试</button>
      </div>
      <div
        v-if="!errorMessage && tableRows.length === 0 && !loading"
        class="empty-message"
      >
        <span>暂无数据</span>
        <button @click="loadReportData" class="retry-btn">加载数据</button>
      </div>
      <div id="example" ref="hotContainer"></div>
    </div>

    <div :class="['side-panel', { 'side-panel--collapsed': !panelOpen }]">
      <button class="panel-toggle" @click="panelOpen = !panelOpen">
        <span v-if="panelOpen">⮜ 收起</span>
        <span v-else>展开 ⮞</span>
      </button>

      <div class="panel-content" v-show="panelOpen">
        <div class="panel-tabs">
          <button
            :class="['tab', activeTab === 'cell' ? 'active' : '']"
            @click="activeTab = 'cell'"
          >
            单元格
          </button>
        </div>

        <div v-if="activeTab === 'cell'" class="panel-section">
          <div class="section-title">基础设置</div>
          <div class="form-item">
            <label>坐标</label>
            <input type="text" :value="displayCoord" disabled />
          </div>
          <div class="form-row">
            <div class="form-item">
              <label>宽度</label>
              <input
                type="number"
                min="20"
                :value="panel.width"
                @change="onWidthChange($event.target.value)"
              />
            </div>
            <div class="form-item">
              <label>高度</label>
              <input
                type="number"
                min="16"
                :value="panel.height"
                :disabled="!canEditHeight"
                @change="onHeightChange($event.target.value)"
              />
            </div>
          </div>
          <div class="form-item">
            <label>值</label>
            <input
              type="text"
              :value="panel.value"
              @change="onValueChange($event.target.value)"
            />
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, computed, onMounted, onBeforeUnmount } from "vue";
import Handsontable from "handsontable";
import "handsontable/styles/handsontable.min.css";
import "handsontable/styles/ht-theme-main.min.css";
import { registerAllModules } from "handsontable/registry";
import { registerLanguageDictionary, zhCN } from "handsontable/i18n";
import { getReportData, saveReportData } from "@/api/report";

registerAllModules();
registerLanguageDictionary(zhCN);

// 响应式数据
const hotInstance = ref(null);
const searchQuery = ref("");
const tableRows = ref([]);
const tableHeaders = ref([]);
const nestedHeaders = ref(null);
const hotContainer = ref(null);
const loading = ref(false);
const errorMessage = ref("");
const pagination = ref(null);

// 右侧面板
const panelOpen = ref(true);
const activeTab = ref("cell");
const panel = ref({ row: -1, col: -1, width: 100, height: 25, value: "" });
const displayCoord = computed(() =>
  panel.value.row >= 0 && panel.value.col >= 0
    ? `${panel.value.row + 1},${panel.value.col + 1}`
    : "-"
);
// 合并块范围与高度可编辑性（仅允许在合并块起始单元格编辑高度）
const currentMergeRange = ref(null);
const canEditHeight = computed(() => {
  if (!currentMergeRange.value) return true;
  return (
    panel.value.row === currentMergeRange.value.row &&
    panel.value.col === currentMergeRange.value.col
  );
});
// 记录用户手动修改过的列宽/行高
const changedCols = ref(new Set());
const changedRows = ref(new Set());

const onSearch = () => {
  if (!hotInstance.value) return;
  const search = hotInstance.value.getPlugin("search");
  search.setQuery(searchQuery.value || "");
  search.search(searchQuery.value || "");
  hotInstance.value.render();
};

const onClearSearch = () => {
  searchQuery.value = "";
  onSearch();
};

const onExportCsv = () => {
  if (!hotInstance.value) return;
  const exporter = hotInstance.value.getPlugin("exportFile");
  exporter.downloadFile("csv", {
    bom: true,
    columnDelimiter: ",",
    columnHeaders: true,
    exportHiddenColumns: false,
    exportHiddenRows: false,
    fileExtension: "csv",
    filename: "handsontable_[YYYY]-[MM]-[DD]",
    mimeType: "text/csv",
    rowDelimiter: "\r\n",
    rowHeaders: true,
  });
};

// Handsontable 初始化
const initHotTable = () => {
  const container = hotContainer.value;
  if (!container) return;
  // 基础配置
  const config = {
    themeName: "ht-theme-main",
    language: "zh-CN",
    data: tableRows.value,
  };

  // 复杂表头
  if (nestedHeaders.value && nestedHeaders.value.length > 0) {
    config.nestedHeaders = nestedHeaders.value.map((level) =>
      level.map((cell) => {
        const headerCell = { label: cell.label || cell };
        if (cell.colspan && cell.colspan > 1) headerCell.colspan = cell.colspan;
        if (cell.level || cell.className) {
          headerCell.className = `${
            cell.level ? `header-level-${cell.level}` : ""
          } ${cell.className || ""}`.trim();
        }
        return headerCell;
      })
    );

    const bottom = nestedHeaders.value[nestedHeaders.value.length - 1];
    config.columns = bottom.map((cell, index) => {
      const label = cell.label || cell;
      const className = cell.className || "";

      if (
        className.includes("cell-number") ||
        label.includes("金额") ||
        label.includes("经费") ||
        label.includes("合计") ||
        label.includes("总计")
      ) {
        return {
          type: "numeric",
          numericFormat: { pattern: "0,0" },
          className: `htRight ${className || "cell-number"}`,
        };
      }

      if (
        className.includes("cell-percent") ||
        label.includes("增长") ||
        label.includes("%")
      ) {
        return {
          type: "numeric",
          className: `htRight ${className || "cell-percent"}`,
        };
      }

      if (
        className.includes("cell-count") ||
        label.includes("数量") ||
        label.includes("排名")
      ) {
        return {
          type: "numeric",
          className: `htCenter ${className || "cell-count"}`,
          readOnly: label.includes("数量") || label.includes("排名"),
        };
      }

      return {
        type: "text",
        className:
          index === 0 ? `htCenter ${className}` : `htLeft ${className}`,
      };
    });
  } else {
    // 简单表头
    config.colHeaders =
      tableHeaders.value.length > 0 ? tableHeaders.value : true;
    config.columns = tableHeaders.value.map((header, index) => {
      if (index >= 3 && index < tableHeaders.value.length - 1) {
        return {
          type: "numeric",
          numericFormat: { pattern: "0,0" },
          className: "htRight cell-number",
        };
      }
      if (index === tableHeaders.value.length - 1) {
        return {
          type: "numeric",
          numericFormat: { pattern: "0,0" },
          className: "htRight cell-total",
          readOnly: true,
        };
      }
      return { type: "text", className: index === 0 ? "htCenter" : "htLeft" };
    });
  }

  Object.assign(config, {
    rowHeaders: false,
    height: "auto",
    autoWrapRow: true,
    autoWrapCol: true,
    stretchH: "all",
    licenseKey: "non-commercial-and-evaluation",
    filters: true,
    dropdownMenu: true,
    contextMenu: true,
    search: true,
    copyPaste: true,
    multiColumnSorting: true,
    manualColumnMove: true,
    manualColumnResize: true,
    manualRowMove: true,
    manualRowResize: true,
    manualColumnFreeze: true,
    fixedColumnsLeft: nestedHeaders.value ? 2 : 1,
    mergeCells: true,
    undo: true,
  });

  const hot = new Handsontable(container, config);
  hotInstance.value = hot;
  // 选择监听
  hot.updateSettings({
    afterSelectionEnd: (r1, c1, r2, c2) => {
      if (r1 === undefined || c1 === undefined) return;
      // 仅取左上角
      const row = Math.min(r1, r2 ?? r1);
      const col = Math.min(c1, c2 ?? c1);
      fillPanelFromCell(row, col);
    },
    afterColumnResize: (col) => {
      if (typeof col === "number") changedCols.value.add(col);
    },
    afterRowResize: (row) => {
      if (typeof row === "number") changedRows.value.add(row);
    },
  });
};

// 加载数据
const loadReportData = async () => {
  loading.value = true;
  errorMessage.value = "";
  try {
    const res = await getReportData({});

    // 同时兼容 { code, data } 与直接 { nestedHeaders, rows }
    const payload =
      res?.data && (res.data.nestedHeaders || res.data.headers || res.data.rows)
        ? res.data
        : res;

    let headers = [];
    let nested = null;
    let rows = [];
    let paginationInfo = null;

    if (payload) {
      if (payload.nestedHeaders && payload.nestedHeaders.length > 0) {
        nested = payload.nestedHeaders;
      } else if (payload.headers) {
        headers = payload.headers;
      }
      rows = payload.rows || [];
      paginationInfo = payload.pagination || null;
    }

    if (rows.length === 0) {
      errorMessage.value = "API 返回数据为空，请检查接口数据";
      tableRows.value = [];
      tableHeaders.value = [];
      nestedHeaders.value = null;
      return;
    }

    nestedHeaders.value = nested;
    tableHeaders.value = nested ? [] : headers;
    tableRows.value = rows;
    pagination.value = paginationInfo;

    if (hotInstance.value) {
      if (nested) {
        hotInstance.value.destroy();
        hotInstance.value = null;
        setTimeout(() => initHotTable(), 100);
      } else {
        hotInstance.value.updateSettings({
          data: tableRows.value,
          colHeaders: tableHeaders.value,
        });
        hotInstance.value.render();
      }
    } else {
      setTimeout(() => initHotTable(), 100);
    }
  } catch (e) {
    console.error("加载数据失败：", e);
    errorMessage.value = `数据加载失败：${e.message || "网络错误"}`;
    tableRows.value = [];
    tableHeaders.value = [];
    nestedHeaders.value = null;
  } finally {
    loading.value = false;
  }
};

onMounted(() => {
  loadReportData();
});

const onMerge = () => {
  if (!hotInstance.value) return;
  const merge = hotInstance.value.getPlugin("mergeCells");
  merge.mergeSelection();
  hotInstance.value.render();
};

const onUnmerge = () => {
  if (!hotInstance.value) return;
  const merge = hotInstance.value.getPlugin("mergeCells");
  merge.unmergeSelection();
  hotInstance.value.render();
};

// 合并/取消合并

onBeforeUnmount(() => {
  if (hotInstance.value) {
    hotInstance.value.destroy();
    hotInstance.value = null;
  }
});

// 获取包含指定单元格的合并范围
const getMergeRange = (row, col) => {
  if (!hotInstance.value) return null;
  const merge = hotInstance.value.getPlugin("mergeCells");
  if (!merge) return null;
  let ranges = [];
  if (typeof merge.getMergedCells === "function") {
    ranges = merge.getMergedCells() || [];
  } else if (
    merge.mergedCellsCollection &&
    Array.isArray(merge.mergedCellsCollection.mergedCells)
  ) {
    ranges = merge.mergedCellsCollection.mergedCells;
  }
  return (
    ranges.find(
      (m) =>
        row >= m.row &&
        row < m.row + m.rowspan &&
        col >= m.col &&
        col < m.col + m.colspan
    ) || null
  );
};

// 从单元格填充面板
const fillPanelFromCell = (row, col) => {
  if (!hotInstance.value) return;
  const hot = hotInstance.value;
  const value = hot.getDataAtCell(row, col);
  const width = hot.getColWidth(col) || 100;
  const range = getMergeRange(row, col);
  currentMergeRange.value = range;
  let height = hot.getRowHeight(row) || 25;
  if (range && range.rowspan > 1) {
    let sum = 0;
    for (let r = range.row; r < range.row + range.rowspan; r++) {
      const h = hot.getRowHeight(r) || 25;
      sum += typeof h === "number" ? h : 25;
    }
    height = sum;
  }
  panel.value = { row, col, width, height, value };
};

// 面板修改应用
const onWidthChange = (val) => {
  if (!hotInstance.value) return;
  const width = Math.max(20, Number(val) || 0);
  panel.value.width = width;
  const plugin = hotInstance.value.getPlugin("manualColumnResize");
  if (plugin && typeof plugin.setManualSize === "function") {
    plugin.setManualSize(panel.value.col, width);
  } else {
    hotInstance.value.updateSettings({
      colWidths: (old) => {
        const arr = Array.isArray(old) ? old.slice() : [];
        arr[panel.value.col] = width;
        return arr;
      },
    });
  }
  hotInstance.value.render();
  changedCols.value.add(panel.value.col);
};

const onHeightChange = (val) => {
  if (!hotInstance.value) return;
  const total = Math.max(16, Number(val) || 0);
  const hot = hotInstance.value;
  const plugin = hot.getPlugin("manualRowResize");
  const range = currentMergeRange.value;
  if (range && range.rowspan > 1) {
    // 仅允许在合并块起始单元格修改整体高度
    if (!(panel.value.row === range.row && panel.value.col === range.col)) {
      return;
    }
    const base = Math.max(16, Math.floor(total / range.rowspan));
    const last = Math.max(16, total - base * (range.rowspan - 1));
    for (let i = 0; i < range.rowspan; i++) {
      const rowIndex = range.row + i;
      const h = i === range.rowspan - 1 ? last : base;
      if (plugin && typeof plugin.setManualSize === "function") {
        plugin.setManualSize(rowIndex, h);
      }
      changedRows.value.add(rowIndex);
    }
  } else {
    if (plugin && typeof plugin.setManualSize === "function") {
      plugin.setManualSize(panel.value.row, total);
    }
    changedRows.value.add(panel.value.row);
  }
  panel.value.height = total;
  hot.render();
};

const onValueChange = (val) => {
  if (!hotInstance.value) return;
  panel.value.value = val;
  hotInstance.value.setDataAtCell(panel.value.row, panel.value.col, val);
};

// 保存（表头/数据 + 尺寸覆盖 + 合并）
const onSave = async () => {
  if (!hotInstance.value) return;
  const hot = hotInstance.value;
  const rows = hot.getData();
  const defaultColWidth = 153;
  const defaultRowHeight = 25;
  const colWidthOverrides = Array.from(changedCols.value)
    .map((col) => {
      const width = hot.getColWidth(col);
      return {
        col,
        width: typeof width === "number" ? width : defaultColWidth,
      };
    })
    .filter((o) => o.width !== defaultColWidth);
  const rowHeightOverrides = Array.from(changedRows.value)
    .map((row) => {
      const height = hot.getRowHeight(row);
      return {
        row,
        height: typeof height === "number" ? height : defaultRowHeight,
      };
    })
    .filter((o) => o.height !== defaultRowHeight);
  // 合并单元格
  let merges = [];
  const mergePlugin = hot.getPlugin("mergeCells");
  if (mergePlugin) {
    if (typeof mergePlugin.getMergedCells === "function") {
      merges = (mergePlugin.getMergedCells() || []).map((m) => ({
        row: m.row,
        col: m.col,
        rowspan: m.rowspan,
        colspan: m.colspan,
      }));
    } else if (
      mergePlugin.mergedCellsCollection &&
      Array.isArray(mergePlugin.mergedCellsCollection.mergedCells)
    ) {
      merges = mergePlugin.mergedCellsCollection.mergedCells.map((m) => ({
        row: m.row,
        col: m.col,
        rowspan: m.rowspan,
        colspan: m.colspan,
      }));
    }
  }
  const payload =
    nestedHeaders.value && nestedHeaders.value.length > 0
      ? {
          nestedHeaders: nestedHeaders.value,
          rows,
          defaults: { colWidth: defaultColWidth, rowHeight: defaultRowHeight },
          colWidthOverrides,
          rowHeightOverrides,
          merges,
        }
      : {
          headers:
            typeof hot.getColHeader === "function"
              ? hot.getColHeader()
              : tableHeaders.value,
          rows,
          defaults: { colWidth: defaultColWidth, rowHeight: defaultRowHeight },
          colWidthOverrides,
          rowHeightOverrides,
          merges,
        };
  try {
    await saveReportData(payload);
    console.log("保存成功", payload);
    alert("保存成功");
  } catch (e) {
    console.error("保存失败", e);
    alert(`保存失败：${e.message || "请求错误"}`);
  }
};
</script>

<style>
.page {
  display: flex;
  align-items: stretch;
  gap: 12px;
}
.main {
  flex: 1 1 auto;
  min-width: 0;
}
.side-panel {
  position: relative;
  width: 300px;
  transition: width 0.2s ease;
  border-left: 1px solid #eee;
}
.side-panel--collapsed {
  width: 42px;
}
.panel-toggle {
  position: absolute;
  left: -12px;
  top: 12px;
  transform: translateX(-100%);
  padding: 2px 6px;
  font-size: 12px;
  background: #fff;
  border: 1px solid #ddd;
  border-radius: 4px;
  cursor: pointer;
}
.panel-content {
  padding: 12px;
}
.panel-tabs {
  display: flex;
  gap: 8px;
  margin-bottom: 8px;
}
.tab {
  padding: 4px 10px;
  border: 1px solid #ddd;
  background: #fafafa;
  cursor: pointer;
  border-radius: 4px;
}
.tab.active {
  background: #fff;
  border-color: #409eff;
  color: #409eff;
}
.panel-section {
  text-align: left;
}
.section-title {
  font-weight: 600;
  margin: 6px 0 10px;
}
.form-item {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 10px;
}
.form-item label {
  width: 48px;
  color: #666;
}
.form-item input {
  flex: 1 1 auto;
  padding: 4px 8px;
  width: 100%;
  min-width: 0;
}
.form-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}
.form-row .form-item {
  width: 100%;
}
.toolbar {
  margin-bottom: 12px;
}
.toolbar input {
  padding: 4px 8px;
  margin-right: 8px;
}
.toolbar button {
  margin-right: 8px;
  padding: 4px 10px;
}
.loading-overlay {
  position: relative;
  padding: 12px;
}
.error-message {
  color: #c00;
  margin: 8px 0;
}
.empty-message {
  color: #666;
  margin: 8px 0;
}
.pagination-info {
  margin: 8px 0;
  color: #555;
}
</style>
